package com.ph.custom.aspect;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.ArrayUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.ui.Model;

import com.ph.custom.annotation.MemberCache;
import com.ph.custom.cenum.UserCacheEnum;
import com.ph.custom.processor.UserCacheAnnotationProcessor;
import com.ph.custom.processor.UserCacheProcessor;
import com.ph.entity.MemberInfo;
import com.ph.shopping.common.util.container.ContainerUtil;

/**
 * 
 * @ClassName:  UserCacheAspect   
 * @Description:用户缓存信息处理
 * @author: lijie
 * @date:   2017年4月8日 上午12:41:42     
 * @Copyright: 2017 www.tydic.com Inc. All rights reserved.
 */
@Aspect
@Component
public class UserCacheAspect {

	private static final Logger LOG = LoggerFactory.getLogger(UserCacheAspect.class);

	@Autowired
	private UserCacheAnnotationProcessor userCacheAnnotationProcessor;

	@Autowired
	private UserCacheProcessor userCacheProcessor;

	/**
	 * 
	 * @Title: userCacheTrack   
	 * @Description: 创建切入点   
	 * @param:       
	 * @return: void      
	 * @throws
	 */
	@Pointcut("execution(* com.ph.controller..*Controller.*(..)) "
			+ "&& @annotation(org.springframework.web.bind.annotation.RequestMapping) "
			+ "&& @annotation(com.ph.custom.annotation.MemberCache)")
	public void userCacheTrack() {}
	/**
	 * 
	 * @Title: operCacheHandle   
	 * @Description: 用户缓存相关操作   
	 * @param: @param point
	 * @param: @return      
	 * @return: Object      
	 * @throws
	 */
	@Around("userCacheTrack()")
	public Object operCacheHandle(ProceedingJoinPoint point) {
		Object result = null;
		try {
			// 方法执行前 执行缓存查询操作 （备注：如果有查询的情况下）
			cacheGetHandle(point);
			result = point.proceed();
			// 方法执行后 执行缓存更新操作 （备注：如果有更新操作的情况下）
			toUpdateCacheHandle(point);
		} catch (Throwable e) {
			LOG.error("aop Around operCacheHandle error", e);
		}
		return result;
	}
	/**
	 * 
	 * @Title: cacheGetHandle   
	 * @Description: 缓存查询处理  
	 * @param: @param point      
	 * @return: void      
	 * @throws
	 */
	private void cacheGetHandle(JoinPoint point) {
		UserCacheEnum[] beforeTargets = { UserCacheEnum.SELECT };
		try {
			cacheHandle(point, beforeTargets);
		} catch (Throwable e) {
			LOG.error("query user cache error", e);
		}
	}
	/**
	 * 
	 * @Title: cacheHandle   
	 * @Description: 缓存处理   
	 * @param: @param point
	 * @param: @param targets
	 * @param: @throws Throwable      
	 * @return: void      
	 * @throws
	 */
	private void cacheHandle(JoinPoint point, UserCacheEnum[] targets) throws Throwable {
		UserCacheEnum[] resoure = checkUserCache(point, targets);
		if (ArrayUtils.isNotEmpty(resoure)) {
			preCacheHandle(point, resoure);
		}
	}
	/**
	 * 
	 * @Title: toUpdateCacheHandle   
	 * @Description: 更新缓存   
	 * @param: @param point      
	 * @return: void      
	 * @throws
	 */
	public void toUpdateCacheHandle(JoinPoint point) {
		UserCacheEnum[] afterTargets = { 
			UserCacheEnum.DELETE, 
			UserCacheEnum.UPDATE, 
			UserCacheEnum.INSERT 
		};
		try {
			cacheHandle(point, afterTargets);
		} catch (Throwable e) {
			LOG.error("user cache to update by After error", e);
		}
	}
	/**
	 * 
	 * @Title: preCacheHandle   
	 * @Description:缓存处理  
	 * @param: @param point
	 * @param: @param targets
	 * @param: @throws Throwable      
	 * @return: void      
	 * @throws
	 */
	private void preCacheHandle(JoinPoint point, UserCacheEnum[] resoure) throws Throwable {
		// 请求对象
		HttpServletRequest request = null;
		// 页面缓存对象
		Model model = null;
		// 会员相关数据
		MemberInfo memberInfo = null;
		// 得到目标方法参数
		Object[] objects = point.getArgs();
		if (ArrayUtils.isNotEmpty(objects)) {
			for (Object object : objects) {
				if (object instanceof HttpServletRequest) {
					request = (HttpServletRequest) object;
				} else if (object instanceof Model) {
					model = (Model) object;
				} else if (object instanceof MemberInfo) {
					memberInfo = (MemberInfo) object;
				}
			}
		}
		// 得到最新的用户信息
		MemberInfo resuslt = backResult(resoure, request, memberInfo);
		// 将需要保存的数据保存到 model
		setModel(model, resuslt, "member");
		// 得到缓存数据将数据回传到需要的地方
		if (memberInfo != null && resuslt != null) {
			BeanUtils.copyProperties(resuslt, memberInfo);
		}
	}
	/**
	 * 
	 * @Title: checkUserCache   
	 * @Description: 校验枚举值   
	 * @param: @param point
	 * @param: @param targets
	 * @param: @return      
	 * @return: UserCacheEnum[]      
	 * @throws
	 */
	private UserCacheEnum[] checkUserCache(JoinPoint point, UserCacheEnum[] targets) {
		UserCacheEnum[] result = null;
		UserCacheEnum[] userCaches = resultResouce(point);
		if (ArrayUtils.isNotEmpty(userCaches)) {
			List<UserCacheEnum> enums = ContainerUtil.aList();
			for (UserCacheEnum uenum : userCaches) {
				if (uenum == null)
					continue;
				if (isTargetExists(targets, uenum)) {
					enums.add(uenum);
				}
			}
			if (!enums.isEmpty()) {
				result = enums.toArray(new UserCacheEnum[enums.size()]);
			}
		}
		return result;
	}
	/**
	 * 
	 * @Title: resultResouce   
	 * @Description:得到注解资源   
	 * @param: @param point
	 * @param: @return      
	 * @return: UserCacheEnum[]      
	 * @throws
	 */
	private UserCacheEnum[] resultResouce(JoinPoint point) {
		UserCacheEnum[] result = null;
		// 得到目标方法签名
		MethodSignature methodSignature = (MethodSignature) point.getSignature();
		if (methodSignature != null) {
			Method method = methodSignature.getMethod();
			if (method != null) {
				MemberCache mCache = userCacheAnnotationProcessor.userAnnotationProcessor(method);
				if(mCache != null){
					result = mCache.userCache();
				}
			}
		}
		return result;
	}
	/**
	 * 
	 * @Title: backResult   
	 * @Description: 处理缓存返回结果   
	 * @param: @param sig
	 * @param: @param request
	 * @param: @param memberInfo
	 * @param: @param targets
	 * @param: @return
	 * @param: @throws Throwable      
	 * @return: MemberInfo      
	 * @throws
	 */
	private MemberInfo backResult(UserCacheEnum[] resoure, HttpServletRequest request, MemberInfo memberInfo)
			throws Throwable {
		MemberInfo resuslt = null;
		if (ArrayUtils.isNotEmpty(resoure)) {
			Arrays.sort(resoure);// 顺序执行获得最新值
			for(int i = 0;i < resoure.length;i++){
				UserCacheEnum uenum = resoure[i];
				if (uenum == null)
					continue;
				resuslt = userCacheProcessor.userCachePreHandle(uenum, MemberInfo.class, memberInfo, request);
			}
		}
		return resuslt;
	}
	/**
	 * 
	 * @Title: setModel   
	 * @Description: 保存数据  
	 * @param: @param model
	 * @param: @param obj
	 * @param: @param key      
	 * @return: void      
	 * @throws
	 */
	private void setModel(Model model, Object obj, String key) {
		if (model != null && obj != null) {
			model.addAttribute(key, obj);
		}
	}
	/**
	 * 
	 * @Title: isTargetExists   
	 * @Description: 查找目标对象   
	 * @param: @param targets
	 * @param: @param target
	 * @param: @return      
	 * @return: boolean      
	 * @throws
	 */
	private boolean isTargetExists(UserCacheEnum[] targets, UserCacheEnum target) {
		Arrays.sort(targets);
		return Arrays.binarySearch(targets, target) >= 0;
	}
}
